/*
 * @文件描述:ADC驱动程序
 * @版本:
 * @作者:周晨阳
 * @Date:2021-10-11 19:34:33
 */
#include "ADC.h"

#if BOARD_INUSE == BOARD_STM32
#include "DSP.h"
#include <math.h>
//a1-a5分别对应为PF6-10，a6为PC0,hand为PC1
u8 sensorMap[7] = {MY_ADC_CHANNEL_4, MY_ADC_CHANNEL_5, MY_ADC_CHANNEL_6, MY_ADC_CHANNEL_7, MY_ADC_CHANNEL_8, MY_ADC_CHANNEL_10, MY_ADC_CHANNEL_11};

/**
 * @brief ADC初始化程序.
 * 
 * @param channel adc频道
 * @param freq 采样频率
 */
void ADC_Inilize(u8 channel, u32 freq)
{
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF | RCC_APB2Periph_ADC3 | RCC_APB2Periph_GPIOC, ENABLE); //使能ADC1通道时钟

    RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
    GPIO_Init(GPIOF, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    ADC_DeInit(ADC3); //复位ADC3

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  //ADC工作模式:独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;                       //模数转换工作在单通道模式
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                 //模数转换工作在单次转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              //ADC数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;                             //顺序进行规则转换的ADC通道的数目
    ADC_Init(ADC3, &ADC_InitStructure);                                 //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器

    ADC_Cmd(ADC3, ENABLE); //使能指定的ADC3

    ADC_ResetCalibration(ADC3); //使能复位校准

    while (ADC_GetResetCalibrationStatus(ADC3))
        ; //等待复位校准结束

    ADC_StartCalibration(ADC3); //开启AD校准

    while (ADC_GetCalibrationStatus(ADC3))
        ; //等待校准结束

    //	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能
}
/**
 * @brief ADC电源控制程序.
 * @deprecated 不再使用
 * @param pwr 
 */
void ADC_PowerControl(u8 pwr)
{
    if (pwr == ENABLE)
    {
    }
    else
    {
    }
}
/**
 * @brief 查询法读一次ADC结果.
 * 
 * @param channel 选择要转换的ADC.
 * @return u16 12位ADC结果.
 */
u16 Get_ADC_Result(u8 channel) //
{
    //设置指定ADC的规则组通道，一个序列，采样时间
    ADC_RegularChannelConfig(ADC3, channel, 1, ADC_SampleTime_239Cycles5); //ADC1,ADC通道,采样时间为239.5周期

    ADC_SoftwareStartConvCmd(ADC3, ENABLE); //使能指定的ADC3的软件转换启动功能

    while (!ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC))
        ; //等待转换结束
    return ADC_GetConversionValue(ADC3);
}

//保存所有传感器的上一个数据
static u16 lastValue[8] = {0};
//所有传感器的限幅滤波阈值
static u8 ThresholdList[8] = {10, 10, 10, 10, 10, 10, 10, 10};

/**
 * @brief 获取角度传感器的ADC初始值
 * 
 * @param angle 角度传感器ID
 * @return u16 ADC初始值
 */
u16 Get_ADC_ResultByAngle(u8 angle) //
{
    u16 newValue = 0;
    //设置指定ADC的规则组通道，一个序列，采样时间
    ADC_RegularChannelConfig(ADC3, sensorMap[angle], 1, ADC_SampleTime_239Cycles5); //ADC1,ADC通道,采样时间为239.5周期

    ADC_SoftwareStartConvCmd(ADC3, ENABLE); //使能指定的ADC3的软件转换启动功能

    while (!ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC))
        ; //等待转换结束

    newValue = ADC_GetConversionValue(ADC3);
    //加入限幅滤波算法
    //如果新值的上一次值的差小于阈值，就直接返回上一次的值
    if (fabs(newValue - lastValue[angle]) < ThresholdList[angle])
    {
        return lastValue[angle];
    }
    //如果新值的上一次值的差大于阈值，就返回新值
    else
    {
        lastValue[angle] = newValue;
        return newValue;
    }
}

/**
 * @brief 获取ADC电压值，单位mv，测量范围0-3.3v
 * 
 * @param channel  ADC channel
 * @return float ADC电压值，单位mv
 */
float getInputVoltage(u8 channel)
{
    return Get_ADC_Result(channel) * 3300.0f / 4096.0f;
}
/**
 * @brief :直接获取角度传感器的电压 ，单位mv，测量范围0-3.3v
 * @param {u8} angle 角度传感器id
 * @return {*}
 */

/**
 * @brief 直接获取角度传感器的电压 ，单位mv，测量范围0-3.3v
 * @param angle  角度传感器id
 * @return float 电压 ，单位mv
 */
float getInputVoltageByAngle(u8 angle)
{
    return Get_ADC_ResultByAngle(angle) * 3300.0f / 4096.0f;
}
/**
 * @brief :角度ID到ADC 频道的转换
 * @param u8 angle
 * @return u8 ADC 频道
 */
u8 angle2ADCMap(u8 angle)
{
    return sensorMap[angle];
}
/**
 * @brief :设置传感器的限幅滤波值
 * @param u8 id
 * @param u8 threshold
 */
void setSensorThreshold(u8 id, u8 threshold)
{
    ThresholdList[id] = threshold;
}
#endif
